package com.lhj.xxsc.order.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.xxsc.common.exception.NoStockExceptoin;
import com.xxsc.common.to.SkuHasStockVo;
import com.xxsc.common.to.mq.OrderTo;
import com.xxsc.common.to.mq.SeckillOrderTo;
import com.xxsc.common.utils.R;
import com.xxsc.common.vo.MemberRespVo;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.lhj.xxsc.order.constant.OrderConstant;
import com.lhj.xxsc.order.constant.RedisLuaScript;
import com.lhj.xxsc.order.entity.OrderItemEntity;
import com.lhj.xxsc.order.entity.PaymentInfoEntity;
import com.lhj.xxsc.order.enume.OrderStatusEnum;
import com.lhj.xxsc.order.feign.CartFeignService;
import com.lhj.xxsc.order.feign.MemberFeignService;
import com.lhj.xxsc.order.feign.ProductFeignService;
import com.lhj.xxsc.order.feign.WmsFeignService;
import com.lhj.xxsc.order.interceptor.LoginUserInterceptor;
import com.lhj.xxsc.order.service.OrderItemService;
import com.lhj.xxsc.order.service.PaymentInfoService;
import com.lhj.xxsc.order.to.OrderCreateTo;
import com.lhj.xxsc.order.vo.*;
import org.bouncycastle.crypto.engines.OldIESEngine;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxsc.common.utils.PageUtils;
import com.xxsc.common.utils.Query;

import com.lhj.xxsc.order.dao.OrderDao;
import com.lhj.xxsc.order.entity.OrderEntity;
import com.lhj.xxsc.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
	private ThreadLocal<OrderSubmitVo> confirmVoThreadLocal = new ThreadLocal<>();
	@Autowired
	MemberFeignService memberFeignService;
	@Autowired
	ProductFeignService productFeignService;
	@Autowired
	CartFeignService cartFeignService;
	@Autowired
	ThreadPoolExecutor executor;
	@Autowired
	WmsFeignService wmsFeignService;
	@Autowired
	StringRedisTemplate redisTemplate;
	@Autowired
	OrderItemService orderItemService;
	@Autowired
	RabbitTemplate rabbitTemplate;
	@Autowired
	PaymentInfoService paymentInfoService;

	@Override
	public PageUtils queryPage(Map<String, Object> params) {
		IPage<OrderEntity> page = this.page(
				new Query<OrderEntity>().getPage(params),
				new QueryWrapper<OrderEntity>()
		);

		return new PageUtils(page);
	}

	@Override
	public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
		MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
		OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
		// 开启服务之前。共享之前的请求头
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

		// 远程调用会员服务查看所有的收货地址
		CompletableFuture<Void> futureAddrs = CompletableFuture.runAsync(() -> {
			// 开启服务之前。共享之前的请求头
			RequestContextHolder.setRequestAttributes(requestAttributes);
			List<MemberAddressVo> address = memberFeignService.getAddress(memberRespVo.getId());
			orderConfirmVo.setAddress(address);
		}, executor);
		// 远程查询购物车服务，查询出所有选中的购物项目
		CompletableFuture<Void> futureProduct = CompletableFuture.runAsync(() -> {
			// 开启服务之前。共享之前的请求头
			RequestContextHolder.setRequestAttributes(requestAttributes);
			List<OrderItemVo> currentUsercartItems = cartFeignService.getCurrentUsercartItems();
			orderConfirmVo.setItems(currentUsercartItems);
		}, executor).thenRunAsync(() -> {
			List<OrderItemVo> items = orderConfirmVo.getItems();
			List<Long> ids = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
			Map<Long, Boolean> stock = wmsFeignService.getSkusHasStock(ids).stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock));
			if (stock != null) {
				orderConfirmVo.setStocks(stock);
			}
		}, executor);
		//获取用户积分
		orderConfirmVo.setIntegration(memberRespVo.getIntegration());
		// 其他数据自动计算

		//TODO 防重令牌
		String payToken = UUID.randomUUID().toString().replace("-", "");
		redisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId(), payToken, 30, TimeUnit.MINUTES);
		orderConfirmVo.setOrderToken(payToken);
		CompletableFuture.allOf(futureAddrs, futureProduct).get();
		return orderConfirmVo;
	}

	/**
	 * 下单方法
	 *
	 * @param vo
	 * @return
	 */
	@Override
	@Transactional
	public SubmitOrderResponseVo submitOrder(OrderSubmitVo vo) throws NoStockExceptoin {
		confirmVoThreadLocal.set(vo);
		SubmitOrderResponseVo orderResponseVo = new SubmitOrderResponseVo();
		orderResponseVo.setCode(0);
		MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
		// 验证令牌
		String orderToken = vo.getOrderToken();
		// 使用lua脚本  String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
		String key = OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId();
		// 原子验证令牌并删除
		Long result = redisTemplate.execute(new DefaultRedisScript<Long>(RedisLuaScript.GET_THEN_DELETE_BY_KEY, Long.class), Arrays.asList(key), orderToken);
		if (result == 0L) {
			// 验证失败
			orderResponseVo.setCode(1);
			return orderResponseVo;
		} else {
			OrderCreateTo order = createOrder();
			// 验价
			BigDecimal payAmount = order.getOrder().getPayAmount();
			BigDecimal payPrice = vo.getPayPrice();
			if (Math.abs(payAmount.subtract(payPrice).doubleValue()) < 0.01) {
				// 金额对比
				saveOrder(order);
				// 锁库存 锁失败就回滚 订单好，订单项，skuId，skuName，num
				WareSkuLockVo wareSkuLockVo = new WareSkuLockVo();
				wareSkuLockVo.setOrderSn(order.getOrder().getOrderSn());
				List<OrderItemVo> orderItemVoList = order.getOrderItems().stream().map(item -> {
					OrderItemVo orderItemVo = new OrderItemVo();
					orderItemVo.setSkuId(item.getSkuId());
					orderItemVo.setCount(item.getSkuQuantity());
					orderItemVo.setTitle(item.getSkuName());
					return orderItemVo;
				}).collect(Collectors.toList());
				wareSkuLockVo.setLocks(orderItemVoList);
				// 远程锁库存
				R r = wmsFeignService.orderLockStock(wareSkuLockVo);
				if (r.getCode() == 0) {
					//成功
					orderResponseVo.setOrder(order.getOrder());
					// 发送消息给MQ
					rabbitTemplate.convertAndSend("order-event-exchange", "order.create.order", order.getOrder());
					return orderResponseVo;
				} else {
					//失败
					String msg = (String) r.get("msg");
					throw new NoStockExceptoin(msg);
				}
			} else {
				orderResponseVo.setCode(2);
				return orderResponseVo;
			}
		}

	}
	/* 高并发下不安全
	String oldToken = redisTemplate.opsForValue().get(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId());
	if (!StringUtils.isEmpty(oldToken) && !StringUtils.isEmpty(orderToken) && orderToken.equals(oldToken)) {
		// 令牌验证通过
		redisTemplate.delete(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId());
	} else {
		// 通过
	}*/
	@Override
	public OrderEntity getOrderByOrderSn(String orderSn) {
		return this.baseMapper.selectOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
	}


	/**
	 * 将订单数据保存进数据库
	 *
	 * @param order
	 */
	private void saveOrder(OrderCreateTo order) {
		OrderEntity orderEntity = order.getOrder();
		orderEntity.setModifyTime(new Date());
		this.save(orderEntity);
		List<OrderItemEntity> orderItems = order.getOrderItems();
		orderItemService.saveBatch(orderItems);
	}

	private OrderCreateTo createOrder() {
		MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
		OrderCreateTo orderCreateTo = new OrderCreateTo();
		// 生成订单号
		String orderSn = IdWorker.getTimeId();
		// 创建订单
		OrderEntity orderEntity = buildOrder(orderSn);

		// 采购项目 订单项
		List<OrderItemEntity> orderItemEntities = buildOrderItems(orderSn);

		// 验价 计算
		computePrice(orderEntity, orderItemEntities);
		orderCreateTo.setOrder(orderEntity);
		orderCreateTo.setOrderItems(orderItemEntities);
		return orderCreateTo;
	}

	private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntities) {
		// 订单价格相关
		BigDecimal total = new BigDecimal("0.0");
		BigDecimal coupon = new BigDecimal("0.0");
		BigDecimal integration = new BigDecimal("0.0");
		BigDecimal promotion = new BigDecimal("0.0");
		BigDecimal gift = new BigDecimal("0.0");
		BigDecimal growth = new BigDecimal("0.0");
		for (OrderItemEntity orderItemEntity : orderItemEntities) {
			// 优惠信息
			BigDecimal realAmount = orderItemEntity.getRealAmount();
			coupon = coupon.add(orderItemEntity.getCouponAmount());
			integration = integration.add(orderItemEntity.getIntegrationAmount());
			promotion = promotion.add(orderItemEntity.getPromotionAmount());
			// 总价格
			total = total.add(realAmount);
			// 积分成长值
			gift = gift.add(new BigDecimal(orderItemEntity.getGiftIntegration().toString()));
			growth = growth.add(new BigDecimal(orderItemEntity.getGiftGrowth().toString()));
		}

		orderEntity.setTotalAmount(total);
		// 实际支付金额
		orderEntity.setPayAmount(total.add(orderEntity.getFreightAmount()));
		orderEntity.setCouponAmount(coupon);
		orderEntity.setIntegrationAmount(integration);
		orderEntity.setPromotionAmount(promotion);
		// 设置积分信息
		orderEntity.setIntegration(gift.intValue());
		orderEntity.setGrowth(growth.intValue());
		orderEntity.setDeleteStatus(0);

	}

	// 创建订单
	private OrderEntity buildOrder(String orderSn) {
		MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
		OrderEntity orderEntity = new OrderEntity();
		OrderSubmitVo orderSubmitVo = confirmVoThreadLocal.get();
		orderEntity.setOrderSn(orderSn);
		orderEntity.setMemberId(memberRespVo.getId());
		R fare = wmsFeignService.getFare(orderSubmitVo.getAddrId());
		if (fare.getCode() == 0) {
			FareVo data = fare.getData(new TypeReference<FareVo>() {
			});
			if (data != null) {
				// 设置运费
				orderEntity.setFreightAmount(data.getFare());
				// 设置收货人信息
				orderEntity.setReceiverCity(data.getAddressVo().getCity());
				orderEntity.setReceiverDetailAddress(data.getAddressVo().getDetailAddress());
				orderEntity.setReceiverName(data.getAddressVo().getName());
				orderEntity.setReceiverPhone(data.getAddressVo().getPhone());
				orderEntity.setReceiverPostCode(data.getAddressVo().getPostCode());
				orderEntity.setReceiverProvince(data.getAddressVo().getProvince());
				orderEntity.setReceiverRegion(data.getAddressVo().getRegion());
			}
		}
		orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
		orderEntity.setAutoConfirmDay(7);
		return orderEntity;
	}

	/**
	 * 所有订单项数据
	 *
	 * @return
	 */
	private List<OrderItemEntity> buildOrderItems(String orderSn) {
		List<OrderItemVo> currentUsercartItems = cartFeignService.getCurrentUsercartItems();
		if (!CollectionUtils.isEmpty(currentUsercartItems)) {
			List<OrderItemEntity> orderItemEntityList = currentUsercartItems.stream().map(cartItem -> {
				OrderItemEntity orderItemEntity = buildOrderItem(cartItem);
				orderItemEntity.setOrderSn(orderSn);
				return orderItemEntity;
			}).collect(Collectors.toList());
			return orderItemEntityList;
		}
		return null;
	}

	// 构建某个订单项
	private OrderItemEntity buildOrderItem(OrderItemVo cartItem) {
		OrderItemEntity orderItemEntity = new OrderItemEntity();
		// 订单信息，订单号 V
		// 商品spu V
		Long skuId = cartItem.getSkuId();
		R r = productFeignService.getSpuInfoBySkuId(skuId);
		if (r.getCode() == 0) {
			SpuInfoVo data = r.getData(new TypeReference<SpuInfoVo>() {
			});
			if (data != null) {
				orderItemEntity.setSpuId(data.getId());
				orderItemEntity.setSpuBrand(data.getBrandId().toString());
				orderItemEntity.setSpuName(data.getSpuName());
				orderItemEntity.setCategoryId(data.getCatalogId());
			}
		}
		// 商品sku信息 V
		orderItemEntity.setSkuId(cartItem.getSkuId());
		orderItemEntity.setSkuName(cartItem.getTitle());
		orderItemEntity.setSkuPic(cartItem.getImage());
		orderItemEntity.setSkuPrice(cartItem.getPrice());
		String skuAttr = StringUtils.collectionToDelimitedString(cartItem.getSkuAttr(), ";");
		orderItemEntity.setSkuAttrsVals(skuAttr);
		orderItemEntity.setSkuQuantity(cartItem.getCount());

		// 优惠信息
		// 积分信息 V
		orderItemEntity.setGiftGrowth(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount().toString())).intValue());
		orderItemEntity.setGiftIntegration(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount().toString())).intValue());
		// 设置订单项价格
		orderItemEntity.setPromotionAmount(new BigDecimal("0"));
		orderItemEntity.setCouponAmount(new BigDecimal("0"));
		orderItemEntity.setIntegrationAmount(new BigDecimal("0"));
		// 当前订单项的实际金额 除去各种优惠
		BigDecimal orign = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity().toString()));
		BigDecimal subtract = orign.subtract(orderItemEntity.getPromotionAmount()).subtract(orderItemEntity.getCouponAmount()).subtract(orderItemEntity.getIntegrationAmount());
		orderItemEntity.setRealAmount(subtract);
		return orderItemEntity;
	}

	/**
	 * 关闭订单
	 *
	 * @param entity
	 */
	@Override
	public void closeOrder(OrderEntity entity) {
		OrderEntity orderEntity = this.getById(entity.getId());
		if (orderEntity.getStatus() == OrderStatusEnum.CREATE_NEW.getCode()) {
			OrderEntity updateOrder = new OrderEntity();
			updateOrder.setId(orderEntity.getId());
			updateOrder.setStatus(OrderStatusEnum.CANCLED.getCode());
			this.updateById(updateOrder);
			OrderTo orderTo = new OrderTo();
			BeanUtils.copyProperties(orderEntity, orderTo);
			// 发送给库存系统，让他在解锁库存。考虑到突发意外，导致解锁库存时，我们的订单还没关闭。
			try {
				// 给数据库保存日志消息
				rabbitTemplate.convertAndSend("order-event-exchange", "order.release.other", orderTo);
			} catch (Exception e) {

			}


		}
	}

	@Override
	public PayVo getOrderPay(String orderSn) {
		PayVo payVo = new PayVo();
		OrderEntity order = this.getOrderByOrderSn(orderSn);
		List<OrderItemEntity> orderItemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderSn));
		OrderItemEntity orderItemEntity = orderItemEntities.get(0);
		BigDecimal amount = order.getPayAmount().setScale(2, BigDecimal.ROUND_UP);
		payVo.setTotal_amount(amount.toString());
		payVo.setOut_trade_no(order.getOrderSn());
		payVo.setSubject(orderItemEntity.getSkuName());
		payVo.setBody(orderItemEntity.getSkuAttrsVals());
		return payVo;
	}

	@Override
	public PageUtils queryPageWithItem(Map<String, Object> params) {
		MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
		Long id = memberRespVo.getId();
		IPage<OrderEntity> page = this.page(
				new Query<OrderEntity>().getPage(params),
				new QueryWrapper<OrderEntity>().eq("member_id", id).orderByDesc("id")
		);
		List<OrderEntity> list = page.getRecords().stream().map(item -> {
			List<OrderItemEntity> itemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", item.getOrderSn()));
			item.setItemEntities(itemEntities);
			return item;
		}).collect(Collectors.toList());
		page.setRecords(list);
		return new PageUtils(page);
	}

	/**
	 * 异步处理
	 *
	 * @param vo
	 * @return
	 */
	@Override
	@Transactional
	public String handlePayResult(PayAsyncVo vo) {
		if (vo != null) {
			// 保存交易流水
			PaymentInfoEntity paymentInfoEntity = new PaymentInfoEntity();
			paymentInfoEntity.setAlipayTradeNo(vo.getTrade_no());
			paymentInfoEntity.setOrderSn(vo.getOut_trade_no());
			paymentInfoEntity.setPaymentStatus(vo.getTrade_status());
			paymentInfoEntity.setCallbackTime(vo.getNotify_time());
			paymentInfoService.save(paymentInfoEntity);
			// 修改订单状态
			if (vo.getTrade_status().equals("TRADE_SUCCESS") || vo.getTrade_status().equals("TRADE_FINISHED")) {
				// 支付成功
				String outTradeNo = vo.getOut_trade_no();
				this.baseMapper.updateOrderPayedStatus(outTradeNo, OrderStatusEnum.PAYED.getCode());
			}

			return "success";
		} else {
			return "error";
		}
	}

	@Override
	@Transactional
	public void createSeckillOrder(SeckillOrderTo entity) {
		//TODO 订单信息
		OrderEntity orderEntity = new OrderEntity();
		orderEntity.setOrderSn(entity.getOrderSn());
		orderEntity.setMemberId(entity.getMemberId());
		orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
		BigDecimal multiply = entity.getSeckillPrice().multiply(new BigDecimal("" + entity.getNum()));
		orderEntity.setPayAmount(multiply);
		this.save(orderEntity);
		// TODO 订单项信息
		OrderItemEntity orderItemEntity = new OrderItemEntity();
		orderItemEntity.setOrderSn(entity.getOrderSn());
		orderItemEntity.setRealAmount(multiply);
		orderItemEntity.setSkuPic(entity.getSkuPic());
		// TODO 获取当前sku 的详细信息进行设置
		orderItemEntity.setSkuQuantity(entity.getNum());
		orderItemService.save(orderItemEntity);
	}

}
